﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Office.Interop.Excel;
using PathDelayFaultRobustObservabilityAnalyzer.Properties;
using TSU.FAMC.ComputerEngineering.Classes.Bdds;
using TSU.FAMC.ComputerEngineering.Classes.BooleanMaths.Fundamental;
using TSU.FAMC.ComputerEngineering.Classes.Circuits.Readers;
using TSU.FAMC.ComputerEngineering.Classes.Diagnostics.PathDelayFaults;

namespace PathDelayFaultRobustObservabilityAnalyzer
{
    public partial class ObservabilityForm : Form
    {
        public ObservabilityForm()
        {
            InitializeComponent();
        }

        private void Button1Click(object sender, EventArgs e)
        {
            if (openFileDialog.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            if (openFileDialog.FileNames.Length == 0)
            {
                MessageBox.Show(Resources.ObservabilityForm_button1_Click_Не_выбрано_ни_одного_файла);
                return;
            }

            // reading files
            var results = new List<ObservabilityResult>();
            foreach (var fileName in openFileDialog.FileNames)
            {
                var circuitName = Path.GetFileNameWithoutExtension(fileName);
                string fileStr;
                try
                {
                    // reading file
                    var streamReader = new StreamReader(fileName);
                    fileStr = streamReader.ReadToEnd();
                }
                catch (Exception ex)
                {
                    results.Add(new ObservabilityResult { Name = circuitName, Status = ObservabilityStatus.Error, Description = ex.Message });
                    continue;
                }

                // reading circuit
                var reader = new CircuitReaderPlain { Input = fileStr };

                try
                {
                    reader.Read();
                }
                catch (Exception ex)
                {
                    results.Add(new ObservabilityResult { Name = circuitName, Status = ObservabilityStatus.Error, Description = ex.Message });
                    continue;
                }

                // building tests
                List<List<FlipFlopStats>> observabilities;
                try
                {
                    observabilities = PathDelayFaultAnalyzer.CalculateRobustObservabilities(reader.Circuit);
                }
                catch (Exception ex)
                {
                    results.Add(new ObservabilityResult { Name = circuitName, Status = ObservabilityStatus.Error, Description = ex.Message });
                    continue;
                }

                // collecting statistics
                results.Add(new ObservabilityResult
                {
                    Name = circuitName,
                    Status = ObservabilityStatus.Success,
                    Observabilities = observabilities
                });
            }


            // saving conditions if required
            if (saveConditionsCheckBox.Checked)
            {
                if (OutputFolderBrowserDialog.ShowDialog() == DialogResult.OK &&
                    OutputFolderBrowserDialog.SelectedPath != String.Empty)
                {
                    var errorsCounter = 0;
                    foreach (var result in results)
                    {
                        foreach (var statsForDifferentOutputs in result.Observabilities)
                        {
                            foreach (var stats in statsForDifferentOutputs)
                            {
                                // writing file
                                var fileName = result.Name + "_" + stats.InputMark + "_to_" + stats.OutputMark + "_conditions.pla";
                                var outputFilePath = OutputFolderBrowserDialog.SelectedPath +
                                                     Path.DirectorySeparatorChar + fileName;

                                var outputStr = "#Circuit " + result.Name + "\r\n";

                                outputStr += "#InputsOrder ";
                                foreach (var inputMark in stats.InputMarks)
                                {
                                    outputStr += inputMark;
                                    if (stats.InputMarks.Last() != inputMark)
                                    {
                                        outputStr += ",";
                                    }
                                }
                                outputStr += "\r\n";

                                outputStr += "#StateVar " + stats.InputMark + "\r\n";
                                outputStr += "#Output " + stats.OutputMark + "\r\n\r\n";

                                foreach (var robustConditionsForPath in stats.RobustSensitezationConditions)
                                {
                                    foreach (DictionaryEntry robustConditionsForConjunction in robustConditionsForPath)
                                    {
                                        outputStr += (Cube)robustConditionsForConjunction.Key + "\r\n";
                                        var cubes = ((OrderedBdd)robustConditionsForConjunction.Value).Odnf().Functions[0].Domain1;
                                        foreach (var cube in cubes)
                                        {
                                            outputStr += cube + "\r\n";
                                        }

                                        if (cubes.Count > 0)
                                        {
                                            outputStr += "\r\n";
                                        }
                                    }

                                    if (robustConditionsForPath.Count > 0)
                                    {
                                        outputStr += "\r\n";
                                    }
                                }

                                try
                                {
                                    var streamWriter = new StreamWriter(outputFilePath);
                                    streamWriter.Write(outputStr);
                                    streamWriter.Close();
                                }
                                catch (Exception)
                                {
                                    errorsCounter++;
                                }
                            }
                        }
                    }

                    if (errorsCounter > 0)
                    {
                        MessageBox.Show(string.Format("Во время записи условий очувствления возникло {0} ошибок", errorsCounter));
                    }
                }
            }


            // writing results to excel

            // preparing excel worksheet
            var objExcel = new Microsoft.Office.Interop.Excel.Application();

            // excel workbook
            var objWorkBook = objExcel.Workbooks.Add(System.Reflection.Missing.Value);

            // excel worksheet
            var objWorkSheet = (Worksheet)objWorkBook.Sheets[1];

            // excel header
            objWorkSheet.Cells[2, 2] = "Название";
            objWorkSheet.Cells[2, 3] = "Входов";
            objWorkSheet.Cells[2, 4] = "Выходов";
            objWorkSheet.Cells[2, 5] = "Триггеров";
            objWorkSheet.Cells[2, 6] = "Триггер";
            objWorkSheet.Cells[2, 7] = "Ср. Наблюдаемость";
            objWorkSheet.Cells[2, 8] = "Ср. Наблюдаемость LoS (+1)";
            objWorkSheet.Cells[2, 9] = "Статус";
            objWorkSheet.Cells[2, 10] = "Описание";

            var line = 3;
            foreach (var result in results)
            {
                objWorkSheet.Cells[line, 2] = result.Name;
                objWorkSheet.Cells[line, 3] = result.Observabilities != null ? (result.Observabilities[0][0].InputMarks.Count - result.Observabilities.Count) : 0;
                objWorkSheet.Cells[line, 4] = result.Observabilities != null ? (result.Observabilities[0][0].OutputMarks.Count - result.Observabilities.Count) : 0;
                objWorkSheet.Cells[line, 5] = result.Observabilities != null ? result.Observabilities.Count : 0;
                
                // observabilities
                var j = 0;
                if (result.Observabilities != null)
                {
                    foreach (var observabilityForDifferentOutputs in result.Observabilities)
                    {
                        // average value
                        objWorkSheet.Cells[line + j, 6] = observabilityForDifferentOutputs[0].InputMark;

                        /*
                        var observabilityForDifferentOutputsStr = string.Empty;
                        var losObservabilityForDifferentOutputsStr = string.Empty;
                        foreach (var outputStats in observabilityForDifferentOutputs)
                        {
                            if (observabilityForDifferentOutputsStr != string.Empty)
                            {
                                observabilityForDifferentOutputsStr += ", ";
                            }

                            if (losObservabilityForDifferentOutputsStr != string.Empty)
                            {
                                losObservabilityForDifferentOutputsStr += ", ";
                            }

                            observabilityForDifferentOutputsStr += outputStats.OutputMark + ":" + outputStats.RobustObservability;
                            losObservabilityForDifferentOutputsStr += outputStats.OutputMark + ":" + outputStats.RobustLosObservability;
                        }
                        */

                        objWorkSheet.Cells[line + j, 7] =
                            observabilityForDifferentOutputs.Average(o => o.RobustObservability);// +"(" + observabilityForDifferentOutputsStr + ")";
                        objWorkSheet.Cells[line + j, 8] =
                            observabilityForDifferentOutputs.Average(o => o.RobustLosObservability);// +"(" + losObservabilityForDifferentOutputsStr + ")";
                        j++;
                    }
                }

                objWorkSheet.Cells[line, 9] = result.Status == ObservabilityStatus.Success ? "Ок" : "Ошибка";
                objWorkSheet.Cells[line, 10] = result.Description;

                line += j;
            }

            // showing excel
            objExcel.Visible = true;
            objExcel.UserControl = true;
        }
    }
}
